package com.coderknock.homework.ioc.proxy;

import com.alibaba.fastjson.JSON;
import com.coderknock.homework.ioc.annotation.IgnoreLog;
import com.coderknock.homework.ioc.util.MethodUtil;
import com.google.common.base.Joiner;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.io.RandomAccessFile;
import java.lang.reflect.Method;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

/**
 * <p>日志记录代理</p>
 *
 * @author 三产
 * @version 1.0
 * @date 2017-06-21
 * @QQGroup 213732117
 * @website http://www.coderknock.com
 * @copyright Copyright 2017 拿客 coderknock.com  All rights reserved.
 * @since JDK 1.8
 */
public class LogProxy implements MethodInterceptor {
    private Enhancer enhancer = new Enhancer();
    SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.sss");
    //向文件中写数据
    SimpleDateFormat dateSimpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
    //从当前系统中获取换行符，默认是"\n"
    String lineSeparator = System.getProperty("line.separator", "\n");

    public Object getProxy(Class clazz) {
        //设置需要创建子类的类
        enhancer.setSuperclass(clazz);
        enhancer.setCallback(this);
        //通过字节码技术动态创建子类实例
        return enhancer.create();
    }

    /**
     * 实现MethodInterceptor接口方法
     *
     * @param obj
     * @param method
     * @param args
     * @param proxy
     * @return
     * @throws Throwable
     */
    @Override
    public Object intercept(Object obj, Method method, Object[] args,
                            MethodProxy proxy) throws Throwable {
        //通过代理类调用父类中的方法
        Object result = proxy.invokeSuper(obj, args);
        Date date = new Date();
        Class superClass = obj.getClass().getSuperclass();
        List<String> params = MethodUtil.getParamNames(superClass, method);
        if (!method.isAnnotationPresent(IgnoreLog.class)) {
            //日志要求按天存储、日志内容包含时间戳，类名，方法名，参数列表，参数值，返回值
            StringBuilder log = new StringBuilder("时间戳：");
            log.append(this.simpleDateFormat.format(date));
            log.append(" 方法签名：");
            log.append(superClass.getName());
            log.append(".");
            log.append(method.getName());
            log.append("(");
            log.append(Joiner.on(",").join(params));
            log.append(")");
            if (result == null) {
                log.append(" 返回值类型：");
                log.append(method.getReturnType().getName());
                log.append(" 返回值：");
                log.append("null");
            } else {
                log.append(" 返回值类型：");
                log.append(result.getClass().getName());
                log.append(" 返回值：");
                log.append(JSON.toJSONString(result));
            }
            log.append(lineSeparator);
            FileChannel fc = new RandomAccessFile(dateSimpleDateFormat.format(date) + ".log", "rw").getChannel();
            //定位到文件末尾
            fc.position(fc.size());
            fc.write(ByteBuffer.wrap(log.toString().getBytes()));
            fc.close();
        }
        return result;
    }
}  